<?php

namespace WebmanGrpc\Memory;

/**
 * 内存管理器
 * 
 * 提供内存使用监控和限制机制
 */
class MemoryManager
{
    /**
     * 内存限制（字节）
     * @var int
     */
    protected static int $memoryLimit = 0;
    
    /**
     * 内存警告阈值（字节）
     * @var int
     */
    protected static int $warningThreshold = 0;
    
    /**
     * 内存使用历史记录
     * @var array
     */
    protected static array $memoryHistory = [];
    
    /**
     * 最大历史记录数
     * @var int
     */
    protected static int $maxHistorySize = 100;
    
    /**
     * 内存使用回调函数
     * @var array
     */
    protected static array $callbacks = [];
    
    /**
     * 是否启用内存监控
     * @var bool
     */
    protected static bool $monitoringEnabled = false;
    
    /**
     * 监控间隔（秒）
     * @var int
     */
    protected static int $monitoringInterval = 5;
    
    /**
     * 最后监控时间
     * @var int
     */
    protected static int $lastMonitorTime = 0;
    
    /**
     * 初始化内存管理器
     * 
     * @param array $options 配置选项
     * @return void
     */
    public static function initialize(array $options = []): void
    {
        $defaultOptions = [
            'memory_limit' => 0,  // 0表示使用PHP配置的限制
            'warning_threshold' => 0,  // 0表示为限制的80%
            'max_history_size' => 100,
            'monitoring_enabled' => false,
            'monitoring_interval' => 5,
        ];
        
        $options = array_merge($defaultOptions, $options);
        
        self::$memoryLimit = $options['memory_limit'] ?: self::parseMemoryLimit(ini_get('memory_limit'));
        self::$warningThreshold = $options['warning_threshold'] ?: (int)(self::$memoryLimit * 0.8);
        self::$maxHistorySize = $options['max_history_size'];
        self::$monitoringEnabled = $options['monitoring_enabled'];
        self::$monitoringInterval = $options['monitoring_interval'];
        self::$lastMonitorTime = time();
    }
    
    /**
     * 解析内存限制字符串
     * 
     * @param string $memoryLimit 内存限制字符串
     * @return int 内存限制（字节）
     */
    protected static function parseMemoryLimit(string $memoryLimit): int
    {
        $limit = strtolower(trim($memoryLimit));
        $unit = substr($limit, -1);
        $value = (int)substr($limit, 0, -1);
        
        switch ($unit) {
            case 'g':
                return $value * 1024 * 1024 * 1024;
            case 'm':
                return $value * 1024 * 1024;
            case 'k':
                return $value * 1024;
            default:
                return (int)$limit;
        }
    }
    
    /**
     * 获取当前内存使用量
     * 
     * @return int 内存使用量（字节）
     */
    public static function getCurrentMemoryUsage(): int
    {
        return memory_get_usage(true);
    }
    
    /**
     * 获取当前内存峰值
     * 
     * @return int 内存峰值（字节）
     */
    public static function getCurrentMemoryPeak(): int
    {
        return memory_get_peak_usage(true);
    }
    
    /**
     * 检查内存是否超过限制
     * 
     * @return bool 是否超过限制
     */
    public static function isMemoryLimitExceeded(): bool
    {
        $current = self::getCurrentMemoryUsage();
        return $current > self::$memoryLimit;
    }
    
    /**
     * 检查内存是否超过警告阈值
     * 
     * @return bool 是否超过警告阈值
     */
    public static function isMemoryWarningThresholdExceeded(): bool
    {
        $current = self::getCurrentMemoryUsage();
        return $current > self::$warningThreshold;
    }
    
    /**
     * 记录内存使用情况
     * 
     * @return void
     */
    public static function recordMemoryUsage(): void
    {
        $timestamp = time();
        $usage = self::getCurrentMemoryUsage();
        $peak = self::getCurrentMemoryPeak();
        
        self::$memoryHistory[] = [
            'timestamp' => $timestamp,
            'usage' => $usage,
            'peak' => $peak,
        ];
        
        // 限制历史记录大小
        if (count(self::$memoryHistory) > self::$maxHistorySize) {
            array_shift(self::$memoryHistory);
        }
        
        // 检查内存状态并触发回调
        self::checkMemoryStatus();
    }
    
    /**
     * 检查内存状态
     * 
     * @return void
     */
    protected static function checkMemoryStatus(): void
    {
        $current = self::getCurrentMemoryUsage();
        
        // 检查是否超过限制
        if (self::isMemoryLimitExceeded()) {
            self::triggerCallbacks('memory_limit_exceeded', [
                'current' => $current,
                'limit' => self::$memoryLimit,
            ]);
        }
        // 检查是否超过警告阈值
        elseif (self::isMemoryWarningThresholdExceeded()) {
            self::triggerCallbacks('memory_warning', [
                'current' => $current,
                'threshold' => self::$warningThreshold,
            ]);
        }
    }
    
    /**
     * 触发回调函数
     * 
     * @param string $event 事件名称
     * @param array $data 事件数据
     * @return void
     */
    protected static function triggerCallbacks(string $event, array $data): void
    {
        if (!isset(self::$callbacks[$event])) {
            return;
        }
        
        foreach (self::$callbacks[$event] as $callback) {
            try {
                call_user_func($callback, $data);
            } catch (\Exception $e) {
                // 忽略回调异常
            }
        }
    }
    
    /**
     * 添加内存事件回调
     * 
     * @param string $event 事件名称
     * @param callable $callback 回调函数
     * @return void
     */
    public static function addCallback(string $event, callable $callback): void
    {
        if (!isset(self::$callbacks[$event])) {
            self::$callbacks[$event] = [];
        }
        
        self::$callbacks[$event][] = $callback;
    }
    
    /**
     * 移除内存事件回调
     * 
     * @param string $event 事件名称
     * @param callable $callback 回调函数
     * @return void
     */
    public static function removeCallback(string $event, callable $callback): void
    {
        if (!isset(self::$callbacks[$event])) {
            return;
        }
        
        self::$callbacks[$event] = array_filter(self::$callbacks[$event], function ($cb) use ($callback) {
            return $cb !== $callback;
        });
    }
    
    /**
     * 获取内存使用历史
     * 
     * @param int $limit 返回记录数限制
     * @return array 内存使用历史
     */
    public static function getMemoryHistory(int $limit = 0): array
    {
        if ($limit > 0) {
            return array_slice(self::$memoryHistory, -$limit);
        }
        
        return self::$memoryHistory;
    }
    
    /**
     * 获取内存统计信息
     * 
     * @return array 内存统计信息
     */
    public static function getMemoryStats(): array
    {
        $current = self::getCurrentMemoryUsage();
        $peak = self::getCurrentMemoryPeak();
        
        return [
            'current' => $current,
            'peak' => $peak,
            'limit' => self::$memoryLimit,
            'warning_threshold' => self::$warningThreshold,
            'usage_percent' => self::$memoryLimit > 0 ? ($current / self::$memoryLimit) * 100 : 0,
            'peak_percent' => self::$memoryLimit > 0 ? ($peak / self::$memoryLimit) * 100 : 0,
            'history_count' => count(self::$memoryHistory),
        ];
    }
    
    /**
     * 尝试释放内存
     * 
     * @return int 释放的内存量（字节）
     */
    public static function tryFreeMemory(): int
    {
        $before = self::getCurrentMemoryUsage();
        
        // 触发垃圾回收
        gc_collect_cycles();
        
        // 清空序列化缓存
        if (class_exists('WebmanGrpc\\Serialization\\MessagePool')) {
            \WebmanGrpc\Serialization\MessagePool::clearSerializationCache();
        }
        
        $after = self::getCurrentMemoryUsage();
        
        return $before - $after;
    }
    
    /**
     * 启用内存监控
     * 
     * @return void
     */
    public static function enableMonitoring(): void
    {
        self::$monitoringEnabled = true;
        self::$lastMonitorTime = time();
    }
    
    /**
     * 禁用内存监控
     * 
     * @return void
     */
    public static function disableMonitoring(): void
    {
        self::$monitoringEnabled = false;
    }
    
    /**
     * 检查是否需要记录内存使用情况
     * 
     * @return bool 是否需要记录
     */
    public static function shouldRecordMemory(): bool
    {
        if (!self::$monitoringEnabled) {
            return false;
        }
        
        $now = time();
        return ($now - self::$lastMonitorTime) >= self::$monitoringInterval;
    }
    
    /**
     * 自动记录内存使用情况（如果需要）
     * 
     * @return void
     */
    public static function autoRecordMemory(): void
    {
        if (self::shouldRecordMemory()) {
            self::recordMemoryUsage();
            self::$lastMonitorTime = time();
        }
    }
}